package middleware

import (
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/redis/go-redis/v9"
	"github.com/starmotioncf/common/log"
	"github.com/starmotioncf/common/openapi"
	"github.com/starmotioncf/soutchatinternal/resp"
	"time"
)

// OpenapiMiddleware 开放api鉴权
type OpenapiMiddleware struct {
	config openapi.Config
	rdb    *redis.Client
}

func NewOpenapiMiddleware(conf openapi.Config, rdb *redis.Client) *OpenapiMiddleware {
	if conf.Timeout > 0 {
		conf.Timeout = time.Minute
	}
	return &OpenapiMiddleware{
		config: conf,
		rdb:    rdb,
	}
}

func (m *OpenapiMiddleware) Handle(ctx *gin.Context) {
	headerParams := openapi.NewHeaderFromReq(ctx.Request)
	if m.config.AppKey != headerParams.AppKey {
		log.WithContext(ctx).Error("appKey error")
		resp.Abort(ctx, 400, errors.New("appKey error"))
		return
	}
	if headerParams.Timestamp == 0 || time.Now().Add(-m.config.Timeout).UnixMilli() > headerParams.Timestamp {
		log.WithContext(ctx).Error("request timeout")
		resp.Abort(ctx, 400, errors.New("request timeout"))
		return
	}
	if !openapi.ValidSignature(headerParams, m.config.AppSecret) {
		log.WithContext(ctx).Error("signature error")
		resp.Abort(ctx, 400, errors.New("signature error"))
		return
	}
	rk := fmt.Sprintf("openapi:%s", headerParams.Nonce)
	if headerParams.Nonce == "" || !m.rdb.SetNX(ctx, rk, "", m.config.Timeout).Val() {
		log.WithContext(ctx).Error("don't repeat request")
		resp.Abort(ctx, 400, errors.New("don't repeat request"))
		return
	}
	ctx.Next()
}
